Глава 17

ВИДИМЫЕ ЭЛЕМЕНТЫ

Любой видимый элемент Turbo Vision имеет два важнейших свойства: он полностью контролирует изображение в пределах выделенного ему участка экрана и знает, как обрабатывать связанные с этим участком события - нажатие на клавиши или отметку мышью. Эти свойства определяются двумя псевдоабстрактными методами объекта TView (этот объект является родителем всех остальных видимых элементов Turbo Vision): Draw и HandleEvent. Метод Draw знает, как рисовать объект, но не знает, когда это нужно делать. Метод HandleEvent, наоборот, знает когда, но не знает как. Эти методы в наибольшей степени воплощают основной принцип программ, управляемых событиями: процесс создания изображений и процесс обработки событий - это два разных процесса в том смысле, что в первом случае мы сообщаем программе как создается изображение, а во втором - когда это нужно делать. Обработке событий посвящена следующая глава.

В этой главе мы рассмотрим некоторые детали технической реализации видимых элементов, которые дадут нам возможность разобраться в том, что именно делает видимый элемент и как он это делает. Эти сведения помогут Вам правильно использовать видимые элементы в Вашей программе.

 

17.1. ТЕРРИТОРИАЛЬНОСТЬ

Видимый элемент владеет прямоугольным участком экрана. Правильно сконструированный элемент обязан заполнять нужным изображением всю выделенную ему область, иначе на экране останется «мусор». Чтобы элемент мог заполнить область, он должен знать координаты закрепленного за ним участка. Эти координаты хранятся в двух полях - Origin и Size, каждое из которых имеет тип TPoint. Поле Origin задает координаты левого верхнего угла области, выделенной элементу, поле Size - размер этой области, т.е. показывает на каком расстоянии от Origin находится его правый нижний угол. Минимальный по размеру видимый элемент, который может хоть что-то вывести на экран, имеет Size.X = Size.Y=1.

Объект TPoint крайне прост, он только определяет координаты некоторой точки на экране и не имеет никаких методов:

type

TPoint = object

X: Integer; {Горизонтальная координата}

Y: Integer; {Вертикальная координата} 

end;

Координаты в Turbo Vision имеют две особенности. Во-первых, они указывают позицию на экране, начиная с 0, а не с 1, как это принято в стандартных для Турбо Паскаля подпрограммах работы с текстовым экраном (например, GotoXY из модуля CRT). Во-вторых, все координаты задаются относительно границ той группы видимых элементов, в которой создается и используется новый элемент. В Turbo Vision любойвидимый элемент входит в состав какой-то группы, поскольку все элементы в конечном счете принадлежат программе, которая сама по себе является группой.

Для указания всех четырех координат видимого элемента и действий над ними используется тип TRect следующего вида:

type

TRect = object

A: TPoint; {Левый верхний угол }

В: TPoint; {Правый нижний угол}

Procedure Assign(XA,YA,XB,YB: Integer);

{Назначает значения параметров полям А и В}

Procedure Copy(R: Trect);

{Устанавливает все поля, равными прямоугольнику R}

Procedure Move(ADX,ADY: Integer);

{Смещает прямоугольник, добавляя ADX к А.Х, В.Х и ADY к А. Y, B.Y}

Procedure Grow(ADX,ADY: Integer); 

{Изменяет размер, вычитая ADX из А.Х и прибавляя ADX к В.Х; вычитая ADY из A.Y и прибавляя ADY к B.Y} 

Procedure Intersect(R: TRect); 

{Изменяет положение и размер прямоугольника до области, определенной пересечением R и текущего положения элемента} 

Procedure Union(R: Trect); 

{Изменяет прямоугольник до области, определяемой объединением R и текущего положения элемента} 

Function Contains(P: TPoint): Boolean; 

{Возвращает TRUE, если точка принадлежит элементу} 

Function Equals(R: Trect): Boolean;

{Возвращает True, если положение и размеры прямоугольника R и элемента одинаковы} 

Function Empty: Boolean; 

{Возвращает TRUE, если элемент пустой, т.е. если его поля Size.X и Size,У. равны нулю} 

end;

С помощью полей Owner^.Origin и Owner^.size видимый элемент может определить положение и размер своего владельца, т.е. той группы, в состав которой он входит, а с помощью метода

Procedure GetExtend(var R: Trect)

получить в R свои текущие координаты (напомню, что положение и размеры большинства видимых элементов могут меняться в ходе работы программы). Обычно обращение к GetExtend используется перед тем, как задать максимально возможные координаты вновь создаваемого видимого элемента. Например, если внутри окна TWindow нужно поместить скроллер так, чтобы он занял всю внутреннюю часть окна, можно использовать такой фрагмент:

type

MyWindow = object (TWindow)

.....

Constructor Init;

.....

end ;

Constructor MyWindow.Init; 

var

S: PScroller{Указатель на скроллер}

R: TRect;

HS, VS: PScrollBar;{Указатели на полосы скроллера}

.....

begin

.....

GetExtend(R) ;{Получаем координаты окна}

R.Grow(-1, -1) ;{Уменьшаем их на 1}

S := New(PScroller,

Init(S, HS, VS)){Создаем скроллер} 

Insert(S);{Помещаем скроллер в окно}

.....

end;

 

17.2. ВЫВОД ИЗОБРАЖЕНИЯ

17.2.1. Заполнение области

Видимый элемент может быть частично или полностью перекрыт другими видимыми элементами. Turbo Vision позволяет располагать окна на экране в произвольном порядке, в том числе и накладывая их друг на друга. С помощью метода

Procedure GetClipRect(var R: TRect)

видимый элемент может получить координаты минимальной площади, которую он должен заполнить в данный момент. Обращение к GetClipRect обычно используется в методе Draw и позволяет до минимума сократить время обновления информации на экране.

Следует помнить, что в правильно построенной программе никакой другой видимый элемент не должен вторгаться в область владения данного элемента. Поэтому, если видимый элемент не заполнит всю выделенную ему область, этого за него не сделает никто другой, и незаполненная область окажется «замусоренной» предыдущим выводом в эту часть экрана.

Для вывода на экран не рекомендуется использовать стандартную процедуру Write (WriteLn), т.к. она заполняет только ту часть экрана, которая необходима для вывода, в то время как длина строки в видимом элементе может быть больше строки вывода. С другой стороны, эта процедура игнорирует границы видимого элемента и может «залезть» в чужую область.

Вывод в Turbo Vision основан на применении методов MoveChar, MoveStr и WriteLine. Все три метода используют переменную типа TDrawBuffer в качестве буфера видеопамяти. Метод MoveChar заполняет буфер нужным символом, например, пробелом или символом Char (#176) - этим символом заполняется фон панели экрана. Метод MoveStr переносит в буфер строку (подстроку), а метод WriteLine переносит буфер в видеопамять и таким образом осуществляет собственно вывод на экран.

Тип TDrawBuffer представляет собой массив слов:

type

TDrawBuffer = array [0..MaxViewWidth-1] of Word;

Константа MaxViewWidth определена в интерфейсной части модуля Views и устанавливает максимально возможную длину вывода (132 символа). Элементы массива задают двухбайтные последовательности, используемые в видеопамяти ПК для размещения кода выводимог/о символа (младший байт) и его атрибутов (старший байт). Байт атрибутов определяет цвет выводимого символа и цвет фона, а также содержит признак мерцания (рис. 17.1).

Рис. 17.1. Байт атрибутов видеопамяти

При обращении к методам MoveChar и MoveStr байт атрибутов задается в качестве одного из параметров обращения. Его можно получить с помощью функции GetColor, параметр обращения к которой определяет нужный номер элемента палитры.

17.2.2. Цвет изображения

Все цвета в Turbo Vision определяются системой палитр: за каждым стандартным видимым элементом закреплен свой набор условных номеров цветов, называемый палитрой. Размер палитры (количество определенных для видимого элемента цветов) зависит от функциональности элемента: чем сложнее элемент, чем больше функций он выполняет, тем богаче его палитра (каждому элементу палитры приписывается некоторая функциональность: один элемент ответственен за фон изображения, другой - за текст, третий выделяет специальные символы и т.д.). Например, для скроллера палитра состоит всего из двух элементов: первый элемент определяет цвет основного текста, второй - цвет выделенного текста. Обычно скроллер входит в качестве терминального видимого объекта в группу, палитра которой будет больше. Например, часто скроллер помещается в окно TWindow, палитра которого насчитывает уже 8 элементов (см. рис. 17.2).

Рис. 17.2. Связь палитры TScroller с палитрой TWindow

Палитры образуют систему связанных друг с другом ссылок: каждый элемент палитры содержит не какой-то конкретный цвет или его код, а целое число, указывающее на номер элемента в палитре своего владельца. Если владелец входит в группу, содержимое его палитры устанавливает связь с нужными элементами палитры этой группы и т.д. Ссылки завершаются на «владельце всех владельцев», т.е. на программе: только палитра TProgram и его потомков содержит не ссылки, а сами байты цветовых атрибутов.

Пусть, например, при формировании изображения в методе Draw скроллера выбран первый элемент палитры (нормальный текст). Этот элемент содержит число 6, указывающее номер шестого элемента палитры владельца TScroller. Если владельцем скроллера является объект TWindow, это число означает ссылку на шестой элемент палитры TWindow, который содержит число 13 как ссылку на тринадцатый элемент владельца окна (рис. 17.2). Если, наконец, владельцем окна является программа, то число 13 - это ссылка на тринадцатый элемент палитры TProgram, который содержит байт атрибутов $1Е, т.е. символы будут выводиться желтым цветом на синем фоне (рис. 17.3).

Чтобы получить цвет элемента, используется обращение к функции GetColor. Эта функция просматривает всю цепочку ссылок от текущего видимого элемента до программы и найденный таким образом байт атрибутов из палитры TProgram возвращает в качестве результата. Параметром обращения к функции является номер элемента палитры видимого объекта. Если указан номер несуществующего в данной палитре элемента, функция вернет атрибуты $CF и изображение будет выводиться мигающими белыми символами на красном фоне. Такого сочетания цветов нет ни в одной стандартной палитре, поэтому появление мигающих бело-красных символов на экране

сигнализирует о непредусмотренном разработчиками Turbo Vision функциональном использовании элемента. Если, например, вставить кнопку TButton в текстовое окно TWindow, то окажется, что первый элемент палитры TButton (нормальный текст кнопки) ссылается на 10-й элемент палитры владельца, в то время как в палитре TWindow только 8 элементов.

Рис. 17.3. Фрагмент палитры TProgram

Чтобы изменить цвет изображения, нужно либо изменить ссылку в палитре элемента или его владельца, либо сменить атрибут цвета в палитре TProgram. На практике обычно меняют палитру TProgram, т.к. она определяет цвет всех родственных элементов. Например, если Вы измените элемент палитры, ответственный за цвет основного текста в окне, одновременно все окна изменят свой цвет нужным образом, что, по всей видимости, будет логически правильным.

Палитры Turbo Vision задаются в виде обычных текстовых строк. Это дает возможность применять к палитрам все операции и преобразования, которые используются при работе со строковыми данными. Для изменения k-го элемента палитры TProgram следует изменить k-ый символ в строке, указатель на которую возвращает функция GetPalette. Пусть, например, нам нужно, чтобы во всех окнах скроллера стандартный цвет текста (желтый на голубом фоне) был заменен на белый на черном фоне. Тогда можно использовать такой прием:

Uses Арр,...; 

type

TMyProgram = object (TApplication) 

Constructor Init;

.....

end;

Constructor TMyProgram.Init; 

begin

GetPaletteA[13] := #$0F; {Задаем белый цвет на черном фоне} 

TApplication.Init {Инициируем программу} 

end;

В этом фрагменте в конструкторе TMyProgram.Init осуществляется замена 13-го элемента палитры: этот элемент отвечает за цвет основного текста скроллера (см. рис. 17.3). После такого изменения во всех скроллерах программы основной текст будет выводиться белыми символами на черном фоне.

Для изменения палитры видимого элемента только одного типа нужно перекрыть его метод GetPalette. Допустим нам необходимо, чтобы скроллер рисовал основной текст таким же цветом, как полосы скроллера. В этом случае мы должны посмотреть, каким по счету элементом в палитре окна-владельца скроллера определяется цвет полос: в нашем примере это элемент с номером 5. Таким образом, палитра скроллера должна содержать значения 5 и 7 вместо прежних 6 и 7 (см. рис. 17.2). Создадим новый объект:

type

TMyScroller = object (TScroller)

Function GetPalette: PPalette; Virtual;

end;

Function TMyScroller.GetPalette: PPalette; 

const

NewColors = #5#7;

NewPalette: String [2] = NewColors; 

begin

GetPalette := @NewPalette 

end;

Существует и менее универсальный, но более простой путь изменения цвета только в одном видимом элементе. Как мы знаем, изображение этого элемента в конечном счете формируется в его методе Draw; если этот метод перекрывается в Вашей программе, а в некоторых случаях, например в скроллере, он должен обязательно перекрывается, то можно воздействовать на цвет непосредственно при обращениях к процедурам MoveChar и MoveStr. Например:

type

MyScroller = object (TScroller) 

Procedure Draw; Virtual;

end;

Procedure MyScroller.Draw; 

var

Color: Byte;

.....

begin

(* Color := GetColor(l); {Стандартный цвет скроллера} *) 

Color := $0F; {Задаем белые символы на черном фоне}

.....

MoveChar(...,...,Color,...); 

MoveStr(...,...,Color);

.....

end;

В этом примере в строке комментария (* ..... *) указывается обычный способ получения стандартного цвета основного текста скроллера. Вместо этого желаемый цвет задается нужными атрибутами в переменной Color, которая затем используется при обращениях к процедурам MoveChar и MoveStr.

Палитра TProgram насчитывает 63 элемента и учитывает все возможные функциональные действия, осуществляемые видимыми элементами (см. прил.П6). Более того, этот объект на самом деле имеет три 63-элементных палитры: CColor (цветная палитра), CBlackWhite (черно-белая) и CMonoChrome (монохромная). В установочной секции модуля Views на основе тестирования аппаратных средств ПК из этих палитр выбирается рабочая палитра, которая затем и будет использоваться при формировании изображений. При необходимости Вы можете переустановить палитру TProgram с помощью глобальной процедуры SetVideoMode, например:

Program MyProgram; Uses 

Views,....; 

var

Main: TApplication;

.....

begin {Начало основной программы} 

SetVideoMode(smBW80); {Выбрать черно-белую палитру} 

Main.Init; {Инициация программы}

.....

end;

Обращение к SetVideoMode должно предшествовать инициации основной программы, работающей в среде Turbo Vision. Параметром обращения к этой процедуре может быть одна из следующих констант:

const

smBW80 = $002; {Черно-белый режим работы цветного адаптера} 

smCO80 = $003; {Цветной режим работы} 

smMono = $007; {Монохроматический адаптер}

Эти константы можно дополнять константой

const

smFont8x8 = $100; {Задает 43/50 строк для экрана EGA/VGA.}

для задания режима вывода 43 или 50 строк на экране дисплея, оснащенного адаптером EGA или VGA. Например:

SetVideoMode(smC080+smFont8x8);

 

17.3. ГРУППЫ

Замечательным свойством видимых элементов Turbo Vision является их способность образовывать группы. Все группы являются потомками абстрактного объекта TGroup. Любая программа в конечном счете наследуется от TProgram или TApplication и, следовательно, является потомком TGroup, т.е. представляет собой группу.

Группа - это просто пустое окно. Главная особенность группы заключается в том, что она может управлять входящими в нее элементами. Как и любой другой видимый элемент, группа должна уметь заполнять нужным изображением выделенную ей часть экрана и обрабатывать все связанные с этой областью события. Однако в большинстве случаев группа обращается за выполнением требуемых действий к своим элементам. Например, визуализация группы происходит исключительно с помощью методов Draw тех элементов, которые образуют группу. С другой стороны, некоторые команды могут относиться к группе в целом. Например, группе может адресоваться команда cmClose (закрыть), в результате которой будет уничтожено изображение группы, т.е. очищен выделенный ей участок экрана. Для реализации этой команды группа будет последовательно передавать ее всем входящим в нее элементам.

Важно помнить, что группа обладает способностью включать в себя видимые подэлементы динамически, в ходе исполнения программы. Как правило, состав группы определяется действиями пользователя: если, например, он нажал командную клавишу, связанную с раскрытием опции главного меню, группа TDesktop, ответственная за рабочую зону экрана, обогащается дополнительными видимыми подэлементами «выпавшего» меню. После нажатия клавиши Esc эти элементы будут удалены из состава группы.

17.3.1. Создание группы и изменение ее состава

Создание группы осуществляется за счет создания экземпляра объекта-наследника TGroup и присоединения к нему всех видимых элементов группы. Любой видимый объект, т.е. наследник TView, имеет два поля: Owner и Next. Поле Owner указывает на владельца этого элемента, а поле Next - на следующий равный ему подэлемент группы. При включении видимого элемента в группу его поля изменяются так, что Owner содержит ссылку на экземпляр группы-владельца, a Next имеет значение NIL. После добавления к группе еще одного элемента поле Next ранее включенного элемента изменяет свое значение и содержит ссылку на этот новый элемент. Таким образом создается связанный список подэлементов группы (рис. 17.4).

Для присоединения элемента должны использоваться методы Insert или ExecView. Метод Insert присоединяет очередной видимый элемент к списку подэлементов группы. В зависимости от набора связанных с подэлементом признаков этот элемент может размещаться в центре (признаки ofCenterX и/или ofCenterY), стать активным (ofSelectable) и, наконец, появиться на экране (sfVisible). После создания подэлемента управление передается следующему за обращением к Insert оператору программы.

Метод ExecView осуществляет те же действия, что и метод Insert, однако после создания видимого подэлемента управление будет передано в него и оператор, следующий за обращением к ExecView, получит управление только после уничтожения этого подэлемента. Более точно процесс взаимодействия с программой элемента, присоединенного к группе методом ExecView, можно описать следующим образом. Любой видимый элемент наследует виртуальный метод Valid, с помощью которого он может сигнализировать своему владельцу о том, насколько успешно он выполнил возложенные на него обязанности. Обычно Valid возвращает True, если успешно создан и размещен в динамической памяти экземпляр объекта, и False,- в противном случае. Объект может перекрыть метод Valid и возвратить False, если он хочет оставить управление у себя,- именно так, например, поступает объект TDialog. Метод ExecView приостанавливает исполнение следующего оператора программы до тех пор, пока все подэлементы группы не вернут Valid = True. Таким образом, метод ExecView используется в том случае, когда среди подэлементов группы есть хотя бы один элемент, реализующий диалог с пользователем.

Метод Delete удаляет подэлемент группы из связанного списка.

Puc. 17.4. Связанный список элементов группы

17.3.2. Z-упорядочение и дерево видимых элементов

Последовательное присоединение подэлементов к группе приводит к так называемому Z-упорядочению видимых элементов. Z-упорядочение - это трехмерная модель видимых элементов, в которой координаты X и Y определяют положение элементов на экране, а координата Z - порядковый номер элемента в группе. Например, на рис. 17.5 показана Z-модель элементов окна с рамкой и скроллером.

В этой модели каждый элемент можно представить в виде стеклянной пластины, накладывающейся на уже существующее изображение. То изображение, которое мы видим на экране, есть проекция трехмерной модели на плоскость XY. Трехмерный образ позволяет «взглянуть» на видимые элементы со стороны и увидеть порядок, в котором они присоединяются к группе.

Важно помнить, что любая группа визуализирует свои подэлементы в порядке, определяемом их Z-упорядочением. Для рис. 17.5 это означает, что сначала создается изображение рамки, очерчивающей все окно, затем на рамку накладываются полосы скроллера, потом - сам скроллер с текстом, а накрывает сверху все изображение и скрепляет его в единое целое прозрачная пластина TWindow.

Для того чтобы группа нашла связанный с ней список подэлементов, используется поле First, входящее в любой видимый объект. Это поле содержит NIL, если данный элемент - терминальный видимый объект; если этот элемент - группа, поле First содержит указатель на первый вставленный в группу подэлемент, т.е. на самый «нижний» элемент в смысле Z-упорядочения. Таким образом, цепочка ссылок First - Next образует дерево видимых элементов, так как каждый элемент Next может быть новой группой и в этом случае его поле First <> NIL.

Рис.17.5. Z-модель видимых элементов окна

Программа Turbo Vision всегда владеет строкой меню, строкой статуса и рабочей зоной экрана, а следовательно, имеет дерево видимых элементов, показанное на рис. 17.6.

Рис. 17.6. Основное дерево видимых элементов TApplication

Отметим, что деревья видимых элементов показывают принадлежность элементов, а не их иерархию в генеалогии объектов Turbo Vision, т.е. связи на рис. 17.6 определяют функциональную подчиненность экземпляров объектов Application, MenuBar, Desktop и StatusLine.

Деревья видимых элементов динамически изменяются в ходе работы программы. Они могут расти, если к программе присоединяются новые группы, или уменьшаться, если эти группы уничтожаются. В отличие от этого генеалогическое дерево объектов может только расти за счет создания потомков.

Все ветви дерева видимых элементов всегда заканчиваются терминальными видимыми объектами.

17.3.3. Активные элементы

Внутри любой группы видимых элементов в каждый момент времени может быть выбран (активизирован) один и только один элемент. Даже если в программе открыто несколько окон с текстом, активным считается только то окно, с которым Вы работаете в данный момент. Более того, поскольку окно представляет собой группу, в нем будет активным лишь один элемент. Если, например, Вы воздействуете мышью на полосу скроллера, будет активна именно эта полоса. Рис. 17.7 иллюстрирует сказанное: на нем показано дерево видимых элементов для двух открытых окон, причем активные элементы выделены двойной рамкой.

 

Puc. 17.7. Цепочка активности видимых элементов просмотра текста

Цепочка активности видимых элементов используется при обработке событий (см. гл.18).

Активный элемент обычно выделяется на экране тем или иным способом. Например, выбранное окно очерчивается двойной рамкой, а остальные - одинарной; внутри диалогового окна активный элемент выделяется яркостью (цветом). С помощью метода Select видимый элемент можно сделать активным по умолчанию в момент его создания. При активизации группы активизируется ее подэлемент, указанный как активный по умолчанию. Пользователю может потребоваться изменить текущий активный видимый элемент. Он может это сделать, манипулируя мышью, или нажав командную клавишу (если элемент связан с командной клавишей), или, наконец, с помощью клавиши Tab.

Заметим, что существуют видимые элементы, которые нельзя сделать активными. Например, не может быть активным видимый элемент TBackground (фон рабочей зоны экрана). В момент создания элемента с помощью признака ofSelectable Вы можете указать, будет ли этот элемент выбираемым, т.е. можно ли его сделать активным в ходе работы программы. Однако, если Вы объявите выбираемым тот же элемент TBackground, он все равно не сможет активизироваться, так как знает, что на самом деле активизация ему недоступна. Точно также на сможет активизироваться рамка окна (заметим, что указать на рамку мышью можно, и программа может, например, перемещать окно с рамкой, однако это еще не означает активизации рамки: рамка не может быть объектом диалога с пользователем). Обычно сброс признака ofSelectable используется для того, чтобы запретить элементу стать активным, он, в принципе, может активизироваться, но его активизация в программе не нужна. Таким способом можно, например, сделать неактивной метку в диалоговом окне и, следовательно, превратить ее в статический поясняющий текст.

 

17.4. МОДАЛЬНЫЕ ВИДИМЫЕ ЭЛЕМЕНТЫ

Все программы в среде Turbo Vision рассчитаны на диалоговый способ взаимодействия с пользователем, а следовательно, в них активно используются точки ветвления, управляемые командами пользователя (точки диалога). В точке диалога создается активный видимый элемент, называемый модальным элементом.

Примером модального элемента является диалоговое окно. Когда в программе создается и активизируется модальный элемент, только этот элемент и его подэлементы могут взаимодействовать с пользователем. Любая часть дерева видимых элементов, не являющаяся модальным элементом или не принадлежащая ему, не может быть активна в этот момент. Если, например, на экране развернуто диалоговое окно, любые отметки мышью вне его пределов или нажатие на не предусмотренные в этом окне командные клавиши будут игнорироваться.

Единственным исключением из этого правила являются командные клавиши и соответствующие поля для мыши, определенные в строке статуса. Эти клавиши (поля) всегда доступны пользователю и нажатие на них (отметка их мышью) обрабатывается модальным элементом точно также, как если бы они были определены в нем, хотя этот элемент может и не владеть строкой статуса.

Чтобы временно исключить из списка активных команду (или группу команд), определенную в строке статуса, используется метод DisableCommands. После завершения работы модального элемента можно восстановить активность команд методом EnableCommands. Параметром обращения к этим методам служит произвольное множество типа TCommandSet, содержащее до 256 кодов команд. В Turbo Vision тип TCommandSet определен следующим образом:

type

TCommandSet = set of Byte;

Таким образом запрещать (и разрешать) можно только те команды, коды которых принадлежат диапазону 0...255.

Временно запрещенные команды выделяются в строке статуса пониженной яркостью (оттенком).

 

17.5. ИЗМЕНЕНИЕ СВОЙСТВ ЭЛЕМЕНТА

Каждый видимый элемент Turbo Vision имеет 5 полей, которые определяют его поведение в диалоговой среде и которые можно использовать для того, чтобы изменить свойства элемента. К этим полям относятся Options, GrowMode, DragMode, State и EventMask. Поле EventMask активно используется в обработчиках событий и описано в гл.18. Поля Options, GrowMode и DragMode доступны как для чтения, так и для записи. Поле State доступно только для чтения и изменить его состояние можно с помощью обращения к методу SetState.

17.5.1. Поле Options

Поле Options представляет собой шестнадцатиразрядное слово, биты (разряды) которого показаны на рис. 17.8.

 

Рис.17.8. Разряды поля Options

ofSelectable

Если этот флаг установлен (имеет значение 1), пользователь может выбрать видимый элемент мышью или клавишей Tab. Если Вы поместили на экран информационный элемент, Вам может потребоваться, чтобы пользователь не мог выбрать его. Например, статические текстовые объекты и рамки окон обычно не могут выбираться и имеют ofSelectable = 0.

ofTopSelect

Видимый элемент будет передвигаться наверх в смысле Z-упорядочения, пока не станет самым верхним среди других равных ему видимых элементов. Этот флаг в основном используется для окон в рабочей зоне экрана. Вы не должны использовать его для видимых элементов в группе.

ofFirstClick

Если флаг сброшен, отметка элемента мышью игнорируется, и наоборот - установленный флаг разрешает выбор элемента мышью. Если в диалоговое окно помещена кнопка, Вы наверняка захотите, выбрать ее мышью, поэтому кнопка имеет ofFirstClick установленным по умолчанию. Но если Вы создаете окно, Вы можете сбросить этот флаг, если хотите, чтобы оно не откликалось на выбор мышью.

ofFramed 

Если флаг установлен, видимый элемент имеет рамку.

ofPreProcess

Если флаг установлен, видимый элемент будет получать и, возможно, обрабатывать активные события до того, как их получит и обработает активный элемент. См. раздел «Фаза» в гл.18.

ofPostProcess

Установленный в 1 флаг ofPostProcess позволяет видимому элементу обрабатывать события после того, как они были получены активным элементом, и при условии, что активный элемент не очистил событие. См. раздел «Фаза» в гл.18.

ofBuffered

Когда этот бит установлен, образ группы при первой ее визуализации автоматически сохраняется в буфере. В следующий раз, когда группе нужно будет визуализиро-ваться, она копирует образ из буфера на экран вместо прорисовки всех своих подэле-ментов, что ускоряет процесс создания изображений. Если программа испытывает недостаток в динамической памяти, монитор памяти Turbo Vision освобождает буферы групп до тех пор, пока запрос к динамической памяти не сможет быть выполнен.

Если группа имеет буфер, вызов метода Lock будет блокировать вывод изображения на экран до тех пор, пока не будет вызван метод Unlock. Сразу после вызова UnLock буфер группы целиком выводится на экран. Блокирование уменьшает мерцание во время сложных корректировок экрана. Например, TDesktop блокирует себя, когда выводит свои подэлементы каскадом или черепицей.

ofTileable

Объекг TDesktop может располагать связанные с ним окна каскадом или черепицей. Если окна располагаются каскадом, каждое следующее окно накладывается на предыдущее и почти полностью перекрывает его; при расположении окон черепицей каждое окно располагается так, чтобы не перекрывать другие окна. Если Вы хотите, чтобы окна располагались каскадом, Вам следует очистить флаг ofTileable, если черепицей - установить его в 1. Если для окна установлен режим вывода каскадом, оно будет занимать одно и то же место на экране, в то время как расположение окон черепицей приводит к изменению их размеров и положения при открытии каждого нового окна.

Расположение видимых элементов черепицей или каскадом 'выполняется в TApplication.HandleEvent очень просто:

cmTile: 

begin

DeskTopA.GetExtent(R);

DeskTopA.Tile(R); 

end;

cmCascade: 

begin

DeskTop^.GetExtent(R);

DeskTop^.Cascade(R); 

end;

ofCenterX

Этот флаг следует установить в 1, если Вы хотите, чтобы видимый элемент центрировался по горизонтали, т.е. вставлялся в группу так, чтобы слева и справа от него было приблизительно одинаковое расстояние до границ группы.

ofCenterY

Флаг обеспечивает центрирование элемента по вертикали. Если Вы хотите, чтобы Ваши окна выглядели одинаково хорошо в режимах 25 и 43/50 строк на экране, следует установить ofCenterY = 1.

ofCentered

Установка этих разрядов обеспечивает центровку видимого элемента относительно границ группы одновременно по горизонтальной и вертикальной осям.

17.5.2. Поле GrowMode

Восьмиразрядное поле GrowMode определяет, как должен изменяться видимый элемент, когда его владелец (группа) изменяет свои размеры. Разряды этого поля показаны на рис. 17.9.

Puc. 17.9. Разряды поля GrowMode

Среда Turbo Vision позволяет изменять размеры окон с помощью мыши: для этого надо «схватить» мышью правый нижний угол окна. Флаги GrowMode определяют, как будут вести себя в этой ситуации вставленные в окно элементы. Напомню, что изображение встроенного элемента всегда отсекается границами группы. Стандартное состояние элементов среды Турбо Паскаль соответствует установленным флагам gfGrowHiX и gfGrowHiY.

gfGrowLoX

Если флаг установлен, левая граница видимого элемента всегда располагается на одинаковом расстоянии от правой границы группы-владельца. Таким образом, при уменьшении горизонтального размера окна вставленный в него видимый элемент смещается влево и, возможно, отсекается левой границей окна.

gfGrowLoY

Если флаг установлен, верхняя граница видимого элемента всегда располагается на одинаковом расстоянии от нижней границы группы, т.е. уменьшение вертикального размера окна приводит к смещению элемента вверх.

gfGrowHiX

Если флаг установлен, правая граница видимого элемента всегда располагается на одинаковом расстоянии от левой границы группы, т.е. при уменьшении горизонтального размера окна видимое на экране положение его внутреннего элемента остается неизменным и, возможно, отсекается правой границей окна.

gfGrowHiY

Если флаг установлен, нижняя граница видимого элемента всегда располагается на одинаковом расстоянии от верхней границы группы, т.е. при уменьшении вертикального размера окна видимое на экране положение его внутреннего элемента останется неизменным. Стандартное состояние элементов среды Турбо Паскаль соответствует установленным флагам gfGrowHiX и gfGrowHiY.

gfGrowAll

Если разряды gfGrowAll установлены в 1, видимый элемент передвигается в процессе изменения размеров своего владельца, отсекаясь его левой и верхней границами.

gfGrowRel

Если флаг установлен, видимый элемент пропорционально изменяет свои размеры при изменении размеров владельца. Вы должны использовать эту опцию только с TWindow, или с наследниками от TWindow, которые присоединяются к панели экрана. В этом случае окна сохраняют свои относительные размеры и положения на экране при переходе от 25 строк к 43/50 строкам и обратно. Этот флаг не предназначен для использования с видимыми элементами внутри окна.

17.5.3. Поле DragMode

Поле DragMode размером в один байт определяет, как ведет себя видимый элемент при перемещении владельца. Напомню, что Turbo Vision позволяет перемещать окно на экране с помощью мыши, если «схватить» мышью верхнюю рамку окна.

Должен заметить, что мне не удалось добиться сколько-нибудь заметных результатов при различных установках поля DragMode. По умолчанию Turbo Vision устанавливает DragMode = 32 = dmLimitLoY.

На рис. 17.10 указаны разряды поля DragMode.

Puc. 17.10. Разряды поля Drag

dmDragMove 

Установленный флаг dmDragMode разрешает перемещать окно с помощью мыши.

dmDragGrow 

Если флаг установлен, окно может изменять свои размеры.

dmLimitLoX

Если флаг установлен, левая сторона видимого элемента не может выходить за границы своего владельца.

dmLimitLoY

Если флаг установлен, верхняя часть видимого элемента не может выходить за границы своего владельца.

dmLimitHiX

Если флаг установлен, правая сторона видимого элемента не может выходить за границы своего владельца.

dmLimitHiY

Если флаг установлен, нижняя часть видимого элемента не может выходить за границы своего владельца.

dmLimitAll

Если флаг установлен, ни одна часть видимого элемента не может выходить за границы своего владельца.

17.5.4. Поле State

Шестнадцатиразрядное поле State хранит различные признаки, определяющие поведение или состояние видимого элемента. На рис. 17.11 показаны разряды поля State.

Puc.17.1l. Разряды поля State

sjVisible

Разрешает визуализировать видимый элемент, если визуализируется его владелец. По умолчанию этот флаг установлен.

sfCursorVis

Разрешает показать курсор внутри видимого элемента. По умолчанию этот флаг очищен.

sfCursorlns

Если этот флаг установлен, курсор будет занимать всю высоту строки, если сброшен, курсор имеет стандартную высоту (две нижних строки развертки).

sfShadow 

Если флаг установлен, видимый элемент имеет «тень».

sfActive

Указывает, является ли данный элемент активным окном или подэлементом активного окна.

sfSelected

Указывает, является ли данный элемент текущим (выбранным) видимым элементом. Каждый объект TGroup имеет поле Current, содержащее указатель на текущий выбранный подэлемент или NIL, если не выбран ни один подэлемент. В каждый момент времени в группе может быть выбран только один подэлемент.

sfFocused

Указывает, принадлежит ли данный элемент цепочке активности видимых элементов, т.е. выбран ли он и все его владельцы в данный момент времени.

sJDragging 

Разрешает изменять размеры элемента.

sfDisable

Флаг запрещает выбирать данный видимый элемент. Если флаг сброшен, элемент можно выбрать мышью или клавишей Tab.

sfModal

Если флаг установлен, данный элемент - это модальный элемент. В программе Turbo Vision всегда имеется один и только один модальный элемент. Обычно это экземпляр TApplication или TDialog. Модальный видимый элемент активизируется вызовом метода ExecView и образует корень активного дерева событий: он перехватывает события и управляет ими до тех пор, пока не будет вызван его метод EndModal (см.гл.18). Модальный элемент может передавать события своим подэлементам и получать события от них, но он никогда не передает события своему владельцу (события локализуются в модальном элементе).

sfExposed

Указывает, виден ли элемент или любая его часть в данный момент времени (элемент может закрываться другими видимыми элементами). Если флаг установлен, метод Exposed данного элемента возвращает значение True.

17.5.5 Воздействие на состояние поля State

В отличие от других полей поле State доступно только для чтения (поля Options, DragMode и GrowMode доступны также и для записи). Это означает, что в программе не может использоваться оператор вида

State := NewState;

Установить новое состояние этого поля можно только с помощью метода SetState, доступного любому видимому элементу. Метод SetState объявлен в Turbo Vision следующим образом:

type

TView = object (TObject) 

Procedure SetState(AState:Word; Enable: Boolean); Virtual;

.....

end;

При обращении к методу параметр AState должен содержать маску разрядов поля State, а признак Enable указывает, должны ли устанавливаться эти разряды (Enable = True) или очищаться (Enable = False).

Отметим, что Turbo Vision вызывает метод SetState всякий раз, когда элемент активизируется или выбирается. Это дает возможность программе устанавливать новое состояние элемента или реагировать на действия пользователя (например, на активизацию видимого элемента). В отличие от этого поля Options, DragMode и GrowMode активизируются только при инициации элемента и далее обычно не меняются.

Видимые элементы часто перекрывают метод SetState, чтобы гибко реагировать на действия пользователя. Например кнопка (объект TButton) просматривает флаги поля State и изменяет свой цвет на бирюзовый, когда становится активной. В следующем примере объект TButton вначале проверяет, принадлежит ли он активному окну, чтобы решить, рисовать себя или нет. Затем он проверяет, выбрана ли кнопка в окне и, если это так, вызывает свой метод MakeDefault, чтобы установить или сбросить (в зависимости от Enable) свою активность по умолчанию:

Procedure TButton.SetState(AState: Word; Enable: Boolean); 

begin

TView.SetState(AState, Enable);

if (AState and (sfSelected + sfActive)) <> 0 then 

DrawView;

if (AState and sfFocused)<> 0 then

MakeDefault(Enable); 

end;

Другой пример: допустим, что Ваша программа включает в себя текстовый редактор и Вы хотите разрешить или запретить все команды редактирования в полосе меню в зависимости от того, открыт редактор или нет. В этом случае Вы можете создать такой метод SetState для текстового редактора:

Procedure TEditor.SetState(AState: Word; Enable: Boolean); 

const

EditorCommands = [cmSearch, cmReplace,cmSearchAgain, 

cmGotoLine, cmFindProc,cmFindError];

begin

TView.SetState(AState, Enable); 

if AState and sfActive <> 0 then

if Enable then EnableCommands(EditorCommands) 

else DisableCommands(EditorCommands);

end;